home *** CD-ROM | disk | FTP | other *** search
Text File | 1985-01-31 | 40.3 KB | 1,318 lines |
-
-
- ARGPAR.H
- by Alexander Abacus
- February 1985 issue
-
-
- /* argparse.h: @(#) macros for parsing command arguments. */
- /* by Alexander B. Abacus */
- /* Computer Language BBS file name: ARGPAR.H */
- /* This file is formatted for readability and may not be used with */
- /* all C compilers. For more portable version see ARGPARSE.H */
-
- #if defined Hargparse
- /* #endfile -- this file already included */
- #else ! defined Hargparse /* first inclusion */
- # define Hargparse /* and really include this file */
-
- # ifdef COMMENT
- /*
- /* Macros defined in this file can be used to parse command line
- /* as it is passed to the main program. Macro MAIN
- /* can be used to produce the header of the function "main()".
- /* Other macros should be used within the body of the function
- /* main(). Macros ArgBEGIN(), ArgLOOP, and ArgEND must be used to
- /* sandwich in the other macros.
- /*
- /* Command arguments can be positional or key letter arguments.
- /* Key letter arguments start with a trigger character. Any
- /* character can be specified as trigger character.
- /* The default trigger character is '-'.
- /*
- /* Key letter arguments can be defined as either flag or text
- /* arguments.
- /*
- /* Flag argument consists of a single key letter that
- /* follows the trigger character. No text is expected after the
- /* flag key letter. If any text follows a flag key letter without
- /* a white space it is interpreted as additional key letters.
- /* If any text follows a flag key letter after a white space
- /* it is interpreted as another argument. Several flag key letters
- /* may follow one trigger character.
- /*
- /* Text argument consists of a single key letter immediately
- /* following a trigger character and followed by text either
- /* immediately or after a white space.
- /*
- /* Positional arguments can be processed either after all
- /* key letter arguments have been processed, or all arguments
- /* can be processed in order, intermixing positional arguments
- /* with key arguments. Double trigger character can be used
- /* to signal the end of key letter arguments. Another mode
- /* is provided, but not recommended, in which the first
- /* positional argument terminates key letter arguments.
- /*
- /*
- /* For both Flag and Text arguments two macros exist:
- /* one that Sets a variable and another that Calls a user
- /* defined function.
- /*
- /* Following flags are predefined and can not be redefined:
- /* '?' Output tutorial information to stderr.
- /* '!' Output debugging information to stderr.
- /* '-' (i.e. trigger character) end of key letter arguments.
- /*
- /*
- /* Macros:
- /*
- /* @(#) ArgTutor( ... ) -- used internally.
- /* Print tutorial message from string array 'tutorial'
- /* to stderr and exit abnormally.
- /*
- /* @(#) MAIN()
- /* Defines header for function main(argc, argv, envp).
- /*
- /* @(#) ArgMAIN is same as ArgBEGIN(argc, argv)
- /*
- /* @(#) ArgBEGIN( ArgumentCountVariable, ArgumentVector )
- /* Begins sandwich that parses command arguments.
- /* Macros described before ArgLOOP are optional.
- /* If present, they must be coded between ArgBEGIN
- /* and ArgLOOP. Those macros override provided defaults.
- /* Each of them should be coded only once, if at all.
- /* Macros described between ArgLOOP and ArgEND should
- /* also be coded between ArgLOOP and ArgEND.
- /* One of those macros must be coded for each key letter
- /* argument.
- /*
- /* @(#) ArgTrigger( TriggerCharacter )
- /* TriggerCharacter is used to recognize key letter arguments.
- /* Default is '-'.
- /*
- /* @(#) ArgDescription( DescriptionStringArray )
- /* Provides text to be printed after an error is detected
- /* while parsing arguments.
- /* char * tutorial[] = { 'Command', 'summary', 0 };
- /*
- /* @(#) ArgKeyLeading
- /* If this macro is coded key arguments must precede positional
- /* arguments. After the first positional argument is recognized,
- /* all following arguments are treated as positional.
- /* This mode is not recommended. It is provided just for the
- /* sake of completeness (many programs parse arguments this way).
- /*
- /* @(#) ArgPosCall( FunctionName )
- /* FunctionName is called for each positional argument.
- /* If positional arguments are to be processed after all
- /* key letter arguments, this macro should be left out.
- /* It defaults to the dummy function "argPos()"
- /* defined in this file. Otherwise a function
- /* should be defined as:
- /* char * functionName( keyCharacter, textString )
- /* char keyCharacter; /* Always contains '\0'. */
- /* char * textString; /* Points to positional argument. */
- /* { ... }
- /*
- /* @(#) ArgMin( MinPositionals )
- /* MinPositionals is minimum number of positional arguments.
- /* If this macro is not coded, the check is not performed.
- /*
- /* @(#) ArgMax( MaxPositionals )
- /* MaxPositionals is maximum number of positional arguments.
- /* If this macro is not coded, the check is not performed.
- /*
- /* @(#) ArgLOOP
- /* This macro marks the end of default override macros.
- /* It is followed by macros describing key letter arguments.
- /*
- /* @(#) ArgFlagSet( KeyLetter, CounterVariable )
- /* Increment counter for this flag.
- /* CounterVariable should be initially zero.
- /*
- /* @(#) ArgTextSet( KeyLetter, PointerVariable )
- /* Set pointer to text argument.
- /*
- /* @(#) ArgFlagCall( KeyLetter, FunctionName )
- /* @(#) ArgTextCall( KeyLetter, FunctionName )
- /* Call user defined function to process key letter argument.
- /* Function must be defined as:
- /* char * functionName( keyCharacter, textString )
- /* char keyCharacter; /* Key letter. */
- /* char * textString; /* NULL for flag, or points to text. */
- /* { ... }
- /* If pointer returned by this function is not NULL,
- /* the tutorial message will be printed to stderr
- /* and abnormal exit will be taken.
- /*
- /* @(#) ArgEND
- /* Ends sandwich that parses command arguments.
- /*
- /* Example of use: See end of this file.
- */
- # endif COMMENT
-
- /*[ A.1 ] Include for debugging. */
-
- # if ! defined FILE
- # include <stdio.h>
- # endif ! defined FILE
-
- # if ! defined Hdebug
- # include "debug.h"
- # endif ! defined Hdebug
-
- /*[ A.2 ] Output tutorial information. */
-
- # define ArgTutor(A_Tutorial) \
- { \
- char ** line; \
- for ( (line = A_Tutorial); ((*line) != (char *) 0); (++line) ) \
- { \
- StdMsg \
- ( stderr \
- , " %s" \
- , *line \
- ); \
- } \
- ABEND(1); \
- } \
-
- /*[ B.1 ] Standard heading for main(). */
-
- # define MAIN() \
- main(argc, argv, envp) \
- int argc; \
- char *argv[]; \
- char *envp[]; \
-
- /*[ B.2 ] Begin sandwich, parse, process positional arguments. */
-
- # define ArgMAIN ArgBEGIN(argc, argv)
-
- # define ArgBEGIN(A_argc, A_argv) \
- { /* Begin block with local variables. Ends with ArgEND. */ \
- struct \
- { \
- int argc; \
- int * ptrArgCount; \
- char ** argVector; \
- char * (*ptrFunction) (); \
- int minPositionals; \
- int maxPositionals; \
- int keysLeading; \
- char keyTrigger; \
- char ** tutorial; \
- \
- char * description[2]; \
- int argIndex; \
- int charIndex; \
- int nextPositional; \
- int noOfPositionals; \
- int keysTerminated; /* ON/OFF switch */ \
- char * textPointer; \
- char * keyPointer; \
- } a0; \
- \
- a0.ptrArgCount = &(A_argc); \
- a0.argc = *a0.ptrArgCount; \
- a0.argVector = (A_argv); \
- a0.minPositionals = -1; \
- a0.maxPositionals = -1; \
- a0.ptrFunction = argPos; \
- a0.keysLeading = 0; \
- a0.keyTrigger = '-'; \
- a0.tutorial = & a0.description[0]; \
- a0.description[0] = "Description of arguments is not provided.\n"; \
- a0.description[1] = (char *) 0; \
-
- /*[ B.3 ] Optional macros to override defaults. */
-
- #define ArgMin(A_Min) a0.minPositionals = (A_Min);
- #define ArgMax(A_Max) a0.maxPositionals = (A_Max);
- #define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
- #define ArgKeyLeading a0.keysLeading = 1;
- #define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
- #define ArgDescription(A_Text) a0.tutorial = (A_Text);
-
- /*[ B.4 ] Begining of argument loop. */
-
- #define ArgLOOP \
- a0.keysTerminated = 0; \
- a0.nextPositional = 1; \
- a0.argIndex = 1; \
- \
- if ( ( a0.argVector[1][0] == a0.keyTrigger ) \
- && ( a0.argVector[1][1] == '!' ) ) \
- { \
- a0.textPointer = & a0.argVector[1][1]; \
- DEBUGIN \
- ( \
- /* if not followed by characters, debug all levels */ \
- if ( (* (a0.textPointer + 1)) == '\0' ) debug[0] = (char) 127; \
- \
- /* if followed by characters, select debugging levels */ \
- while ( (* ++a0.textPointer) != '\0' ) \
- { /* for all characters following -! */ \
- if ((* a0.textPointer) < 128) ++debug[* a0.textPointer]; \
- } /* for all characters following -! */ \
- ) /* DEBUGIN */ \
- DEBUGOUT \
- ( \
- StdMsg \
- ( stderr \
- , " Compiled without debugging code. Option -! ineffective.\n" \
- ); \
- ) /* DEBUGOUT */ \
- ++a0.argIndex; \
- } \
- \
- for ( (a0.argIndex); (a0.argIndex < a0.argc); (++a0.argIndex) ) \
- { /* for all arguments */ \
- if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger ) \
- || ( a0.keysTerminated != 0 ) \
- || ( a0.argVector[a0.argIndex][1] == '\0' ) ) \
- { /* not a key: bubble up positional arguments */ \
- DEBUG \
- ( 3, \
- StdMsg \
- ( stderr \
- , "Positional argument %d \"%s\".\n" \
- , a0.nextPositional \
- , a0.argVector[a0.argIndex] \
- ); \
- ) /* DEBUG */ \
- if \
- ( ( a0.maxPositionals >= 0 ) \
- && ( a0.nextPositional > a0.maxPositionals ) \
- ) \
- { /* if(too many positionals) */ \
- StdMsg \
- ( stderr \
- , " Stop. Maximum %d positional arguments, excess at \"%s\".\n" \
- , a0.maxPositionals \
- , a0.argVector[a0.argIndex] \
- ); \
- ArgTutor( a0.tutorial ); \
- } /* if(too many positionals) */ \
- a0.keysTerminated |= a0.keysLeading; \
- a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex]; \
- (void) (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] ); \
- ++a0.nextPositional; \
- } \
- else /* it is a key */ \
- { \
- DEBUG \
- ( 3, \
- StdMsg \
- ( stderr \
- , "Key argument \"%s\".\n" \
- , a0.argVector[a0.argIndex] \
- ); \
- ) /* DEBUG */ \
- a0.charIndex = 0; \
- a0.keyPointer = & a0.argVector[a0.argIndex][0]; \
- do \
- { /* for all characters in an argument */ \
- ++a0.charIndex; \
- ++a0.keyPointer; \
- DEBUG \
- ( 3, \
- StdMsg \
- ( stderr \
- , "Key letter \'%c\'.\n" \
- , *a0.keyPointer \
- ); \
- ) /* DEBUG */ \
- if ( a0.keyPointer[0] == a0.keyTrigger ) \
- { \
- if ( a0.charIndex != 1 ) \
- { \
- StdMsg \
- ( stderr \
- , " Stop. Terminator of keys must be alone: \"%s\".\n" \
- , a0.argVector[a0.argIndex] \
- ); \
- ArgTutor( a0.tutorial ); \
- } \
- if ( a0.keyPointer[1] != '\0' ) \
- { \
- StdMsg \
- ( stderr \
- , " Stop. Terminator of keys followed by: \"%s\".\n" \
- , a0.argVector[a0.argIndex] \
- ); \
- ArgTutor( a0.tutorial ); \
- } \
- a0.keysTerminated = 1; \
- } \
- else \
- { \
- switch ( a0.keyPointer[0] ) \
- { \
- case '?': \
- ArgTutor( a0.tutorial ); \
- EXIT( a0.argc != 2); \
-
- # ifdef COMMENT
- /*
- /* The previous and the following macro form the sandwich into which
- /* macro calls defining key letter arguments will be inserted.
- /* Comunication between macros making up the sandwich is through
- /* the members of the structure declared in the previous macro.
- /* The structure is local to the sandwich.
- */
- # endif COMMENT
-
- /*[ B.5 ] End sandwich, verify number of positional arguments. */
-
- # define ArgEND \
- default: \
- StdMsg \
- ( stderr \
- , " Stop. Key letter \'%c\' rejected.\n" \
- , *a0.keyPointer \
- ); \
- ArgTutor( a0.tutorial ); \
- break; \
- } /* switch */ \
- } /* if not double trigger */ \
- } /* for all characters in argument */ \
- while ( a0.keyPointer != (char *) 0 ); \
- } /* if key or not a key */ \
- } /* for all arguments */ \
- \
- a0.noOfPositionals = a0.nextPositional - 1; \
- \
- if \
- ( ( a0.minPositionals >= 0 ) \
- && ( a0.noOfPositionals < a0.minPositionals ) \
- ) \
- { /* if(too few positionals) */ \
- StdMsg \
- ( stderr \
- , " Stop. Minimum %d positional arguments, %d supplied.\n" \
- , a0.minPositionals \
- , a0.noOfPositionals \
- ); \
- ArgTutor( a0.tutorial ); \
- } /* if(too few positionals) */ \
- \
- (* a0.ptrArgCount) = a0.noOfPositionals; \
- } /* End block begun with ArgBEGIN. */ \
-
- /*[ C.1 ] Key-letter flag argument, deferred processing. */
-
- # define ArgFlagSet(A_KeyLetter, A_FlagCounter) \
- case A_KeyLetter: \
- ++A_FlagCounter; \
- DEBUG \
- ( 3, \
- StdMsg \
- ( stderr \
- , "Flag \'%c\' accepted, occurance number %d.\n" \
- , *a0.keyPointer \
- , A_FlagCounter \
- ); \
- ) /* DEBUG */ \
- break; \
-
- /*[ C.2 ] Key-letter flag argument, immediate processing. */
-
- # define ArgFlagCall(A_KeyLetter, A_FlagFunction) \
- case A_KeyLetter: \
- DEBUG \
- ( 3, \
- StdMsg \
- ( stderr \
- , "Flag \'%c\' accepted, function \"%s()\" called.\n" \
- , *a0.keyPointer \
- , "A_FlagFunction" \
- ); \
- ) /* DEBUG */ \
- if (A_FlagFunction ( *a0.keyPointer, (char *) 0 ) != (char *) 0 ) \
- { \
- ArgTutor( a0.tutorial ); \
- } \
- break; \
-
- /*[ C.3 ] Key-letter text argument, deferred processing. */
-
- # define ArgTextSet(A_KeyLetter, A_TextPointer) \
- case A_KeyLetter: \
- if ( A_TextPointer != (char *) 0 ) \
- { \
- StdMsg \
- ( stderr \
- , " Stop. Repeated key-letter '%c' with text.\n" \
- , A_KeyLetter \
- ); \
- ArgTutor( a0.tutorial ); \
- } \
- argText \
- ( & A_TextPointer \
- , & a0.keyPointer \
- , & a0.argIndex \
- , a0.charIndex \
- , a0.keyTrigger \
- , a0.argc \
- , a0.argVector \
- , a0.tutorial \
- ); \
- break; \
-
- /*[ C.4 ] Key-letter text argument, immediate processing. */
-
- # define ArgTextCall(A_KeyLetter, A_TextFunction) \
- case A_KeyLetter: \
- argText \
- ( & a0.textPointer \
- , & a0.keyPointer \
- , & a0.argIndex \
- , a0.charIndex \
- , a0.keyTrigger \
- , a0.argc \
- , a0.argVector \
- , a0.tutorial \
- ); \
- if(A_TextFunction ( A_KeyLetter, a0.textPointer ) != (char *) 0 ) \
- { \
- ArgTutor( a0.tutorial ); \
- } \
- break; \
-
- /*[ D.1 ] Dummy function for processing positional arguments. */
-
- static
- char * argPos( a_keyChar, a_argString )
- char a_keyChar;
- char * a_argString;
- {
- START ( '0', "argPos", 0 )
- RETURN ( (char) 0 );
- }
-
- /*[ D.2 ] Function common for key-letter text arguments. */
-
- static Void argText
- ( a_textPointer
- , a_keyPointer
- , a_argIndex
- , a_charIndex
- , a_keyTrigger
- , a_argc
- , a_argv
- , a_tutorial
- )
- char ** a_textPointer;
- char ** a_keyPointer;
- int * a_argIndex;
- int a_charIndex;
- char a_keyTrigger;
- int a_argc;
- char * a_argv[];
- char * a_tutorial[];
- { /* argText() */
- START('0', "argText", "(string) \"%s\"")
-
- if ( a_charIndex != 1 )
- {
- StdMsg
- ( stderr
- , " Stop. Key letter with text must stand alone: \"%s\".\n"
- , a_argv[*a_argIndex]
- );
- ArgTutor( & a_tutorial[0] );
- }
- else if ( ( (*a_keyPointer)[1]) != '\0' )
- { /* text following key letter without a separating white space */
- (*a_textPointer) = (char *) & (*a_keyPointer)[1];
- }
- else /* text must be in the following argument */
- {
- ++(*a_argIndex);
- if ( ((*a_argIndex) >= a_argc)
- || (a_keyTrigger == *a_argv[*a_argIndex]) )
- { /* text is missing */
- StdMsg
- ( stderr
- , " Stop. Text not found after key letter \"%s\".\n"
- , *a_keyPointer
- );
- --(*a_argIndex);
- ArgTutor( & a_tutorial[0] );
- }
- else
- {
- (*a_textPointer) = (char *) a_argv[*a_argIndex];
- } /* endif */
- } /* endif */
-
- DEBUG
- ( 3,
- StdMsg
- ( stderr
- , "Key letter \'%c\' with text \"%s\".\n"
- , ** a_keyPointer
- , * a_textPointer
- );
- ) /* DEBUG */
-
- (*a_keyPointer) = (char *) 0;
- RETURN ( Nothing );
- } /* argText() */
-
- /* --------------------------------------------------------------- */
-
- # if defined DriverH
- # undef DriverH
-
- /* T.1: Test driver for this include. */
-
- #define Storage static
- #include "debug.h"
-
- static char * tutorial[] =
- {
- "Expected arguments are: file1 file2 \n",
- " file1 is the source, \n",
- " file2 is the target. \n",
- 0
- };
-
- main(argCount, argVector)
- int argCount;
- char * argVector[];
- {
- int f_flag = 0;
- char *t_text = (char *) 0;
- START('m', "main", 0)
-
- ArgBEGIN (argCount, argVector)
- ArgMin (1)
- ArgMax (2)
- ArgDescription(tutorial)
- ArgLOOP
- ArgFlagSet ('f', f_flag)
- ArgTextSet ('t', t_text)
- ArgFlagCall ('F', argPos)
- ArgTextCall ('T', argPos)
- ArgEND
-
- EXIT (0);
- } /* main */
-
- # endif DriverH
-
- #endif Hargparse
-
- /* argparse.h: End of file. */
-
- *********************************************************************
-
-
- Other files of importance
- by Alexander Abacus
-
-
- ARGBEGIN.H
-
-
- /* argbegin.h: @(#) Begin argument parsing sandwich, see argparse.h */
- /* by Alexander B. Abacus */
-
- #ifndef ArgCount
- #define ArgCount argc
- #endif
-
- #ifndef ArgVector
- #define ArgVector argv
- #endif
-
- { /* Begin block with local variables. Ends with argend.h */
- struct
- {
- char ** tutorial;
- char ** argVector;
- char * description[2];
- char * textPointer;
- char * keyPointer;
- char * (*ptrFunction) ();
- int * ptrArgCount;
- int argc;
- int minPositionals;
- int maxPositionals;
- int keysLeading;
- int argIndex;
- int charIndex;
- int nextPositional;
- int noOfPositionals;
- int keysTerminated; /* ON/OFF switch */
- char keyTrigger;
- } a0;
-
- a0.ptrArgCount = &(ArgCount);
- a0.argc = *a0.ptrArgCount;
- a0.argVector = (ArgVector);
- a0.minPositionals = -1;
- a0.maxPositionals = -1;
- a0.ptrFunction = argPos;
- a0.keysLeading = 0;
- a0.keyTrigger = '-';
- a0.tutorial = & a0.description[0];
- a0.description[0] = "Description of arguments is not provided.\n";
- a0.description[1] = (char *) 0;
-
- /* argbegin.h: End of file. */
-
-
- ARGEND.H
-
- /* argend.h: @(#) End sandwichbegun with argbegin.h, see argparse.h */
- /* by Alexander B. Abacus */
-
- default:
- fprintf
- ( stderr
- , " Stop. Key letter \'%c\' rejected.\n"
- , *a0.keyPointer
- );
- ArgTutor( a0.tutorial );
- break;
- } /* switch */
- } /* if not double trigger */
- } /* for all characters in argument */
- while ( a0.keyPointer != (char *) 0 );
- } /* if key or not a key */
- } /* for all arguments */
-
- a0.noOfPositionals = a0.nextPositional - 1;
-
- if
- ( ( a0.minPositionals >= 0 )
- && ( a0.noOfPositionals < a0.minPositionals )
- )
- { /* if(too few positionals) */
- fprintf
- ( stderr
- , " Stop. Minimum %d positional arguments, %d supplied.\n"
- , a0.minPositionals
- , a0.noOfPositionals
- );
- ArgTutor( a0.tutorial );
- } /* if(too few positionals) */
-
- (* a0.ptrArgCount) = a0.noOfPositionals;
- } /* End block begun with argbegin.h */
-
- /* argend.h: End of file. */
-
-
- ARGLOOP.H
-
- /* argloop.h: @(#) Begining of argument loop, see argparse.h */
- /* by Alexander B. Abacus */
-
- a0.keysTerminated = 0;
- a0.nextPositional = 1;
- a0.argIndex = 1;
-
- if ( ( a0.argVector[1][0] == a0.keyTrigger )
- && ( a0.argVector[1][1] == '!' ) )
- {
- a0.textPointer = & a0.argVector[1][1];
- #ifdef Debug
- /* if not followed by characters, debug all levels */
- if ( (* (a0.textPointer + 1)) == '\0' ) debug[0] = (char) 127;
-
- /* if followed by characters, select debugging levels */
- while ( (* ++a0.textPointer) != '\0' )
- { /* for all characters following -! */
- if ((* a0.textPointer) < 128) ++debug[* a0.textPointer];
- } /* for all characters following -! */
- #else ! defined Debug
- fprintf
- ( stderr
- , " Compiled without debugging code. Option -! ineffective.\n"
- );
- #endif Debug
- ++a0.argIndex;
- }
-
- for ( (a0.argIndex); (a0.argIndex < a0.argc); (++a0.argIndex) )
- { /* for all arguments */
- #ifdef DriverH
- fprintf ( stderr, "Word %d \"%s\".\n", a0.argIndex, a0.argVector[a0.argIndex] );
- #endif DriverH
-
- if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger )
- || ( a0.keysTerminated != 0 )
- || ( a0.argVector[a0.argIndex][1] == '\0' ) )
- { /* not a key: bubble up positional arguments */
- if
- ( ( a0.maxPositionals >= 0 )
- && ( a0.nextPositional > a0.maxPositionals )
- )
- { /* if(too many positionals) */
- fprintf
- ( stderr
- , " Stop. Maximum %d positional arguments, excess at \"%s\".\n"
- , a0.maxPositionals
- , a0.argVector[a0.argIndex]
- );
- ArgTutor( a0.tutorial );
- } /* if(too many positionals) */
- a0.keysTerminated |= a0.keysLeading;
- a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex];
- /* (void) */ (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] );
- ++a0.nextPositional;
- }
- else /* it is a key */
- {
- a0.charIndex = 0;
- a0.keyPointer = & a0.argVector[a0.argIndex][0];
- do
- { /* for all characters in an argument */
- ++a0.charIndex;
- ++a0.keyPointer;
- if ( (*a0.keyPointer) == '\0' ) { break; } /* from do ... while */
- #ifdef DriverH
- fprintf( stderr, "Remaining argument: \"%s\".\n", a0.keyPointer );
- #endif DriverH
-
- if ( a0.keyPointer[0] == a0.keyTrigger )
- {
- if ( a0.charIndex != 1 )
- {
- fprintf
- ( stderr
- , " Stop. Terminator of keys must be alone: \"%s\".\n"
- , a0.argVector[a0.argIndex]
- );
- ArgTutor( a0.tutorial );
- }
- if ( a0.keyPointer[1] != '\0' )
- {
- fprintf
- ( stderr
- , " Stop. Terminator of keys followed by: \"%s\".\n"
- , a0.argVector[a0.argIndex]
- );
- ArgTutor( a0.tutorial );
- }
- a0.keysTerminated = 1;
- }
- else
- {
- switch ( a0.keyPointer[0] )
- {
- case '?':
- ArgTutor( a0.tutorial );
- exit( a0.argc != 2);
-
- /* argloop.h: End of file. */
-
-
- ARGPAR.1
-
-
-
- Listing 1
- to
- Macros Special Series on C Macros
- February 1985
-
-
- >> Simplified argument parsing, positional and flag <<
-
-
-
- #define ArgBEGIN(A_argc, A_argv) \
- { /* Begin block with local variables. Ends with ArgEND. */ \
- struct \
- { int argc, *ptrArgCount; \
- char ** argVector; \
- char * (*ptrFunction) (); \
- char keyTrigger, *keyPointer; \
- int argIndex, charIndex, nextPositional, keysTerminated; \
- } a0; \
- a0.ptrArgCount = &(A_argc); a0.argVector = (A_argv); \
- a0.argc = *a0.ptrArgCount; a0.keyTrigger = '-'; \
- a0.ptrFunction = argPos;
-
- #define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
- #define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
-
- #define ArgLOOP \
- a0.keysTerminated = 0; a0.nextPositional = 1; \
- for ( (a0.argIndex = 1); (a0.argIndex < a0.argc); (++a0.argIndex) ) \
- { /* for all arguments */ \
- if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger ) \
- || ( a0.keysTerminated != 0 ) \
- || ( a0.argVector[a0.argIndex][1] == '\0' ) ) \
- { /* not a key: bubble up positional arguments */ \
- a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex]; \
- (void) (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] ); \
- ++a0.nextPositional; \
- } \
- else /* it is a key */ \
- { \
- for \
- ( (a0.charIndex = 1, a0.keyPointer = & a0.argVector[a0.argIndex][1]) \
- ; ( ( a0.keyPointer != (char *) 0 ) \
- && ( (*a0.keyPointer) != '\0' ) \
- ) \
- ; (++a0.charIndex, ++a0.keyPointer) \
- ) \
- { /* for all characters in an argument */ \
- switch ( a0.keyPointer[0] ) \
- {
-
- #define ArgFlagSet(A_KeyLetter, A_FlagCounter) \
- case A_KeyLetter: ++A_FlagCounter; break;
-
- #define ArgFlagCall(A_KeyLetter, A_Function) \
- case A_KeyLetter: (A_Function)( *a0.keyPointer, 0 ); break;
-
- #define ArgEND \
- default: \
- (void) fprintf \รจ ( stderr \
- , " Stop. Key letter \'%c\' rejected.\n" \
- , *a0.keyPointer \
- ); \
- exit (1); \
- } /* switch */ \
- } /* for all characters in argument */ \
- } /* if key or not a key */ \
- } /* for all arguments */ \
- (* a0.ptrArgCount) = a0.nextPositional - 1; \
- } /* End block begun with ArgBEGIN. */ \
-
- static char * argPos( a_keyChar, a_argString )
- char a_keyChar, *a_argString;
- { return ( (char *) 0 ); }
-
- /* --------------------------------------------------------------- */
-
- #if defined DriverH
-
- #include <stdio.h>
-
- void main(argCount, argVector)
- int argCount;
- char * argVector[];
- {
- int f_flag = 0;
-
- ArgBEGIN (argCount, argVector)
- ArgPosCall (argPos)
- ArgTrigger ('-')
- ArgLOOP
- ArgFlagSet ('f', f_flag)
- ArgFlagCall ('F', argPos)
- ArgEND
-
- exit (0);
- } /* main */
-
- #endif DriverH
-
-
- ARGPARSE.H
-
- /* argparse.h: @(#) macros for parsing command arguments. */
- /* by Alexander B. Abacus */
- /* Computer Language BBS file name ARGPARSE.H */
- /* This and related files make a more portable version of ARGPAR.H */
- /* related files: argparse.use, argbegin.h, argloop.h, argend.h */
-
- #ifdef Hargsmall
- /* #endfile -- this file already included */
- #else ! defined Hargparse /* first inclusion */
-
- #define Hargsmall
- /* and really include this file */
- /*[ A.1 ] Required include. */
-
- #ifndef FILE
- #include <stdio.h>
- #endif ! defined FILE
-
- /*[ A.2 ] Output tutorial information. */
-
- /* void */ ArgTutor(line)
- char ** line;
- {
- for ( (line); ((*line) != (char *) 0); (++line) )
- {
- fprintf
- ( stderr
- , " %s"
- , *line
- );
- }
- exit(1);
- }
-
- /*[ A.3 ] Dummy function for processing positional arguments. */
-
- static
- char * argPos( a_keyChar, a_argString )
- char a_keyChar;
- char * a_argString;
- {
- #ifdef DriverH
- fprintf ( stderr, "Argument" );
- if ( a_keyChar != '\0' )
- {
- fprintf ( stderr, " key-letter \'%c\'", a_keyChar );
- }
- if ( a_argString != (char *) 0 )
- {
- fprintf ( stderr, " text \"%s\"", a_argString );
- }
- fprintf ( stderr, ".\n" );
- #endif DriverH
- return ( (char *) 0 );
- }
-
- /*[ B.1 ] Standard heading for main(). */
-
- #define MAIN() main(argc, argv, envp) int argc; char *argv[]; char *envp[];
-
- /*[ B.2 ] Optional macros to override defaults. */
-
- #define ArgMin(A_Min) a0.minPositionals = (A_Min);
- #define ArgMax(A_Max) a0.maxPositionals = (A_Max);
- #define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
- #define ArgKeyLeading a0.keysLeading = 1;
- #define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
- #define ArgDescription(A_Text) a0.tutorial = (A_Text);
-
- /*[ C.1 ] Key-letter flag argument, deferred processing. */
-
- #define ArgFlagSet(A_KeyLetter, A_FlagCounter) case A_KeyLetter: ++A_FlagCounter; break;
-
- /*[ C.2 ] Key-letter flag argument, immediate processing. */
-
- #define ArgFlagCall(A_KeyLetter, A_FlagFunction) case A_KeyLetter: if (A_FlagFunction ( *a0.keyPointer, (char *) 0 ) != (char *) 0 ) { ArgTutor( a0.tutorial ); } break;
-
-
- /*[ C.3 ] Key-letter text argument, deferred processing. */
-
- #define ArgTextSet(A_KeyLetter, A_TextPointer) \
- case A_KeyLetter: \
- argText \
- ( & A_TextPointer \
- , & a0.keyPointer \
- , & a0.argIndex \
- , a0.charIndex \
- , a0.keyTrigger \
- , a0.argc \
- , a0.argVector \
- , a0.tutorial \
- , A_KeyLetter \
- , 0 \
- ); \
- break;
-
- /*[ C.4 ] Key-letter text argument, immediate processing. */
-
- #define ArgTextCall(A_KeyLetter, A_TextFunction) \
- case A_KeyLetter: \
- argText \
- ( & a0.textPointer \
- , & a0.keyPointer \
- , & a0.argIndex \
- , a0.charIndex \
- , a0.keyTrigger \
- , a0.argc \
- , a0.argVector \
- , a0.tutorial \
- , A_KeyLetter \
- , A_TextFunction \
- ); \
- break;
-
- /*[ D.2 ] Function common for key-letter text arguments. */
-
- static /* void */ argText
- ( a_textPointer
- , a_keyPointer
- , a_argIndex
- , a_charIndex
- , a_keyTrigger
- , a_argc
- , a_argv
- , a_tutorial
- , a_keyLetter
- , a_textFunction
- )
- char ** a_textPointer;
- char ** a_keyPointer;
- int * a_argIndex;
- int a_charIndex;
- char a_keyTrigger;
- int a_argc;
- char * a_argv[];
- char * a_tutorial[];
- char a_keyLetter;
- char * (*a_textFunction) ();
- { /* argText() */
- if ( a_textFunction == 0 )
- { /* ArgTextSet */
- if ( (* a_textPointer) != (char *) 0 )
- { /* second occurance of this key letter */
- fprintf
- ( stderr
- , " Stop. Repeated key-letter '%c' with text.\n"
- , a_keyLetter
- );
- ArgTutor( a_tutorial );
- } /* second occurance of this key letter */
- } /* ArgTextSet */
-
- if ( a_charIndex != 1 )
- {
- fprintf
- ( stderr
- , " Stop. Key letter with text must stand alone: \"%s\".\n"
- , a_argv[*a_argIndex]
- );
- ArgTutor( & a_tutorial[0] );
- }
- else if ( ( (*a_keyPointer)[1]) != '\0' )
- { /* text following key letter without a separating white space */
- (*a_textPointer) = (char *) & (*a_keyPointer)[1];
- }
- else /* text must be in the following argument */
- {
- ++(*a_argIndex);
- if ( ((*a_argIndex) >= a_argc)
- || (a_keyTrigger == *a_argv[*a_argIndex]) )
- { /* text is missing */
- fprintf
- ( stderr
- , " Stop. Text not found after key letter \"%s\".\n"
- , *a_keyPointer
- );
- --(*a_argIndex);
- ArgTutor( & a_tutorial[0] );
- }
- else
- {
- (*a_textPointer) = (char *) a_argv[*a_argIndex];
- } /* endif */
- } /* endif */
-
- if ( a_textFunction != 0 )
- { /* ArgTextCall */
- if((*a_textFunction) ( a_keyLetter, (* a_textPointer) ) != (char *) 0 )
- {
- ArgTutor( a_tutorial );
- }
- } /* ArgTextCall */
-
- (*a_keyPointer) = (char *) 0; /* to skip to next element of argv */
-
- return;
- } /* argText() */
-
- /* --------------------------------------------------------------- */
-
- #ifdef DriverH
-
- /* T.1: Test driver for this include. */
-
- static char * tutorial[] =
- {
- "Expected arguments are: file1 file2 \n",
- " file1 is the source, \n",
- " file2 is the target. \n",
- 0
- };
-
- main(argCount, argVector)
- int argCount;
- char * argVector[];
- {
- int f_flag = 0;
- char *t_text = (char *) 0;
-
- #define ArgCount argCount
- #define ArgVector argVector
- #include "argbegin.h"
- ArgMin (1)
- ArgMax (2)
- ArgDescription(tutorial)
- #include "argloop.h"
- ArgFlagSet ('f', f_flag)
- ArgFlagCall ('F', argPos)
- ArgTextSet ('t', t_text)
- ArgTextCall ('T', argPos)
- #include "argend.h"
-
- fprintf ( stderr, "Flag counter: %d.\n", f_flag );
- if ( t_text != (char *) 0 )
- {
- fprintf ( stderr, "Text: \"%s\".\n", t_text );
- }
-
- exit (0);
- } /* main */
-
- #endif DriverH
-
- #endif Hargsmall
-
- /* argparse.h: End of file. */
-
-
- ARGPARSE.USE
-
-
- #ifdef COMMENT
- /*
- /* This file describes the use of files: argparse.h, argbegin.h, argloop.h,
- /* and argend.h. Those files make a more portable implementation of the
- /* macros defined and described in the file argpar.h.
- /* The most important difference is that macros ArgBEGIN(), ArgLOOP, and
- /* ArgEND have been replaced with include files argbegin.h, argloop.h, and
- /* argend.h. Text of those macros exceeds buffer sizes of C preprocessors
- /* on micro-computers.
- /*
- /* Macros described in this file can be used to parse command line
- /* as it is passed to the main program. Macro MAIN
- /* can be used to produce the header of the function "main()".
- /* Other macros should be used within the body of the function
- /* main(). Includes argbegin.h, argloop.h, and argend.h must be used to
- /* sandwich in the macros.
- /*
- /* Command arguments can be positional or key letter arguments.
- /* Key letter arguments start with a trigger character. Any
- /* character can be specified as trigger character.
- /* The default trigger character is '-'.
- /*
- /* Key letter arguments can be defined as either flag or text
- /* arguments.
- /*
- /* Flag argument consists of a single key letter that
- /* follows the trigger character. No text is expected after the
- /* flag key letter. If any text follows a flag key letter without
- /* a white space it is interpreted as additional key letters.
- /* If any text follows a flag key letter after a white space
- /* it is interpreted as another argument. Several flag key letters
- /* may follow one trigger character.
- /*
- /* Text argument consists of a single key letter immediately
- /* following a trigger character and followed by text either
- /* immediately or after a white space.
- /*
- /* Positional arguments can be processed either after all
- /* key letter arguments have been processed, or all arguments
- /* can be processed in order, intermixing positional arguments
- /* with key arguments. Double trigger character can be used
- /* to signal the end of key letter arguments. Another mode
- /* is provided, but not recommended, in which the first
- /* positional argument terminates key letter arguments.
- /*
- /*
- /* For both Flag and Text arguments two macros exist:
- /* one that Sets a variable and another that Calls a user
- /* defined function.
- /*
- /* Following flags are predefined and can not be redefined:
- /* '?' Output tutorial information to stderr.
- /* '!' Output debugging information to stderr.
- /* '-' (i.e. trigger character) end of key letter arguments.
- /*
- /*
- /* Macros:
- /*
- /* @(#) ArgTutor( ... ) -- used internally.
- /* Print tutorial message from string array 'tutorial'
- /* to stderr and exit abnormally.
- /*
- /* @(#) MAIN()
- /* Defines header for function main(argc, argv, envp).
- /*
- /* @(#) #define ArgCount argc
- /* @(#) #define ArgVector argv
- /* @(#) #include 'argbegin.h'
- /* Begins sandwich that parses command arguments.
- /* Macros described before argloop.h are optional.
- /* If present, they must be coded between argbegin.h
- /* and argloop.h. Those macros override provided defaults.
- /* Each of them should be coded only once, if at all.
- /* Macros described between argloop.h and argend.h should
- /* also be coded between argloop.h and argend.h.
- /* One of those macros must be coded for each key letter
- /* argument.
- /*
- /* @(#) ArgTrigger( TriggerCharacter )
- /* TriggerCharacter is used to recognize key letter arguments.
- /* Default is '-'.
- /*
- /* @(#) ArgDescription( DescriptionStringArray )
- /* Provides text to be printed after an error is detected
- /* while parsing arguments.
- /* char * tutorial[] = { 'Command', 'summary', 0 };
- /*
- /* @(#) ArgKeyLeading
- /* If this macro is coded key arguments must precede positional
- /* arguments. After the first positional argument is recognized,
- /* all following arguments are treated as positional.
- /* This mode is not recommended. It is provided just for the
- /* sake of completeness (many programs parse arguments this way).
- /*
- /* @(#) ArgPosCall( FunctionName )
- /* FunctionName is called for each positional argument.
- /* If positional arguments are to be processed after all
- /* key letter arguments, this macro should be left out.
- /* It defaults to the dummy function "argPos()"
- /* defined in this file. Otherwise a function
- /* should be defined as:
- /* char * functionName( keyCharacter, textString )
- /* char keyCharacter; /* Always contains '\0'. */
- /* char * textString; /* Points to positional argument. */
- /* { ... }
- /*
- /* @(#) ArgMin( MinPositionals )
- /* MinPositionals is minimum number of positional arguments.
- /* If this macro is not coded, the check is not performed.
- /*
- /* @(#) ArgMax( MaxPositionals )
- /* MaxPositionals is maximum number of positional arguments.
- /* If this macro is not coded, the check is not performed.
- /*
- /* @(#) #include 'argloop.h'
- /* This macro marks the end of default override macros.
- /* It is followed by macros describing key letter arguments.
- /*
- /* @(#) ArgFlagSet( KeyLetter, CounterVariable )
- /* Increment counter for this flag.
- /* CounterVariable should be initially zero.
- /*
- /* @(#) ArgTextSet( KeyLetter, PointerVariable )
- /* Set pointer to text argument.
- /*
- /* @(#) ArgFlagCall( KeyLetter, FunctionName )
- /* @(#) ArgTextCall( KeyLetter, FunctionName )
- /* Call user defined function to process key letter argument.
- /* Function must be defined as:
- /* char * functionName( keyCharacter, textString )
- /* char keyCharacter; /* Key letter. */
- /* char * textString; /* NULL for flag, or points to text. */
- /* { ... }
- /* If pointer returned by this function is not NULL,
- /* the tutorial message will be printed to stderr
- /* and abnormal exit will be taken.
- /*
- /* @(#) #include 'argend.h'
- /* Ends sandwich that parses command arguments.
- /*
- /* Example of use: See end of file argparse.h.
- */
- #endif COMMENT
-